added Feb 2001 SDK
[windows-sources.git] / shared source / vb / language / shared / tinylock.h
blobe492b842f1bc299752ddd46f12bc32f1098ac615
1 //-------------------------------------------------------------------------------------------------
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // Smallest possible implementation of an exclusive lock.
6 //
7 //-------------------------------------------------------------------------------------------------
9 #pragma once
11 class CTinyLock
13 private:
14 volatile DWORD m_dwOwner; // Owning thread (non-zero means locked)
16 void Spin (long *piSpinCount)
18 if ((*piSpinCount)-- < 0)
20 InterlockedIncrement (&m_iSleeps);
21 Snooze();
22 *piSpinCount = m_iSpinStart;
24 else if (*piSpinCount == (m_iSpinStart - 1))
26 InterlockedIncrement (&m_iSpins);
30 public:
31 static LONG m_iSpins;
32 static LONG m_iSleeps;
33 static LONG m_iSpinStart;
35 public:
36 CTinyLock() : m_dwOwner(0)
38 if (m_iSpinStart == -1)
40 SYSTEM_INFO si;
41 GetSystemInfo (&si);
42 if (si.dwNumberOfProcessors > 1)
43 m_iSpinStart = 4000; // Hard-coded spin count...
44 else
45 m_iSpinStart = 0;
49 ////////////////////////////////////////////////////////////////////////////
50 // CTinyLock::Acquire -- lock this object, returning true if this is the
51 // first lock, false otherwise. If true is returned, Release() must be
52 // called to unlock the object.
54 bool Acquire ()
56 long iSpin = m_iSpinStart;
57 DWORD dwOld, dwTid = GetCurrentThreadId();
59 while (true)
61 dwOld = (DWORD)InterlockedCompareExchange ((LONG*) & m_dwOwner, (LONG)dwTid, 0);
62 if (dwOld == 0 || dwOld == dwTid)
63 break;
64 Spin (&iSpin);
67 return dwOld == 0;
70 ////////////////////////////////////////////////////////////////////////////
71 // CTinyLock::Release -- release the lock held by this thread. This should
72 // NOT be called if Acquire() returned false, indicating that this thread
73 // already had this object locked.
75 void Release ()
77 VSASSERT (m_dwOwner == GetCurrentThreadId(), "Invalid");
78 m_dwOwner = 0;
81 ////////////////////////////////////////////////////////////////////////////
82 // CTinyLock::LockedByMe -- tests the lock to see if this thread currently
83 // has it locked.
84 bool LockedByMe ()
86 return m_dwOwner == GetCurrentThreadId();
89 int CountLockedByMe ()
91 return m_dwOwner == GetCurrentThreadId() ? 1 : 0;
94 ////////////////////////////////////////////////////////////////////////////
95 // CTinyLock::IsLocked -- tests the lock to see if it is locked or not (by
96 // any thread)
98 bool IsLocked ()
100 return m_dwOwner != 0;
103 ////////////////////////////////////////////////////////////////////////////////
104 // Snooze
106 // This is a friendly way to give up a time slice. It uses Sleep(1), which
107 // allows lower-priority threads to execute, and then calls PeekMessage, which
108 // allows sent messages to be processed by this thread (allowing COM/RPC messages
109 // to go through, etc.)
110 static inline void Snooze ()
112 // #ifndef FEATURE_PAL
113 // MSG msg;
114 // Sleep(1);
115 // PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
116 //#else
117 SwitchToThread();
118 //#endif
122 ////////////////////////////////////////////////////////////////////////////////
123 // CTinyGate -- handles scope-locking for a CTinyLock object
125 class CTinyGate
127 private:
128 CTinyLock *m_pLock;
129 bool m_fLocked;
131 public:
132 CTinyGate(CTinyLock *p) : m_pLock(p)
134 m_fLocked = m_pLock && m_pLock->Acquire();
137 ~CTinyGate()
139 Release ();
142 void Release()
144 if (m_fLocked)
146 m_pLock->Release();
147 m_fLocked = false;
151 void Acquire()
153 VSASSERT(!m_fLocked, "Invalid");
154 m_fLocked = m_pLock && m_pLock->Acquire();
157 bool HasLocked() const
159 return m_fLocked;